home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 5
/
Aminet 5 - March 1995.iso
/
Aminet
/
game
/
role
/
Ang261Lib.lha
/
src
/
store1.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-10-22
|
15KB
|
535 lines
/*
* store1.c: store code, updating store inventory, pricing objects
*
* Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
*
* This software may be copied and distributed for educational, research, and
* not for profit purposes provided that this copyright and statement are
* included in all such copies.
*/
#include "constant.h"
#include "config.h"
#include "types.h"
#include "externs.h"
#ifdef USG
#ifndef ATARIST_MWC
#include <string.h>
#endif
#else
#include <strings.h>
#endif
#ifndef NO_LINT_ARGS
#ifdef __STDC__
static void special_offer(inven_type *);
static void insert_store(int, int, int32, struct inven_type *);
static void store_create(int);
#else
static void special_offer();
static void insert_store();
static void store_create();
#endif
#endif
/* Returns the value for any given object -RAK- */
int32
item_value(i_ptr)
register inven_type *i_ptr;
{
register int32 value;
value = i_ptr->cost;
/* don't purchase known cursed items */
if (i_ptr->ident & ID_DAMD)
value = 0;
/* Weapons and armor */
else if (((i_ptr->tval >= TV_BOW) && (i_ptr->tval <= TV_SWORD)) ||
((i_ptr->tval >= TV_BOOTS) && (i_ptr->tval <= TV_SOFT_ARMOR))) {
if (!known2_p(i_ptr))
value = object_list[i_ptr->index].cost;
else if ((i_ptr->tval >= TV_BOW) && (i_ptr->tval <= TV_SWORD)) {
if (i_ptr->tohit < 0)
value = 0;
else if (i_ptr->todam < 0)
value = 0;
else if (i_ptr->toac < 0)
value = 0;
else
value = i_ptr->cost + (i_ptr->tohit + i_ptr->todam + i_ptr->toac) * 100;
} else {
if (i_ptr->toac < 0)
value = 0;
else
value = i_ptr->cost + i_ptr->toac * 100;
}
} else if (((i_ptr->tval >= TV_SLING_AMMO) && (i_ptr->tval <= TV_ARROW))
|| (i_ptr->tval == TV_SPIKE)) { /* Ammo */
if (!known2_p(i_ptr))
value = object_list[i_ptr->index].cost;
else {
if (i_ptr->tohit < 0)
value = 0;
else if (i_ptr->todam < 0)
value = 0;
else if (i_ptr->toac < 0)
value = 0;
else
/* use 5, because missiles generally appear in groups of 20, so
* 20 * 5 == 100, which is comparable to weapon bonus above
*/
value = i_ptr->cost + (i_ptr->tohit + i_ptr->todam + i_ptr->toac) * 5;
}
/* Potions, Scrolls, and Food */
} else if ((i_ptr->tval == TV_SCROLL1) || (i_ptr->tval == TV_SCROLL2) ||
(i_ptr->tval == TV_POTION1) || (i_ptr->tval == TV_POTION2)) {
if (!known1_p(i_ptr))
value = 20;
} else if (i_ptr->tval == TV_FOOD) {
if ((i_ptr->subval < (ITEM_SINGLE_STACK_MIN + MAX_MUSH))
&& !known1_p(i_ptr))
value = 1;
/* Rings and amulets */
} else if ((i_ptr->tval == TV_AMULET) || (i_ptr->tval == TV_RING)) {
/* player does not know what type of ring/amulet this is */
if (!known1_p(i_ptr))
value = 45;
else if (!known2_p(i_ptr))
/* player knows what type of ring, but does not know whether it is
* cursed or not, if refuse to buy cursed objects here, then player
* can use this to 'identify' cursed objects
*/
value = object_list[i_ptr->index].cost;
/* Wands and staffs */
} else if ((i_ptr->tval == TV_STAFF) || (i_ptr->tval == TV_WAND)) {
if (!known1_p(i_ptr)) {
if (i_ptr->tval == TV_WAND)
value = 50;
else
value = 70;
} else if (known2_p(i_ptr))
value = i_ptr->cost + (i_ptr->cost / 20) * i_ptr->p1;
}
/* picks and shovels */
else if (i_ptr->tval == TV_DIGGING) {
if (!known2_p(i_ptr))
value = object_list[i_ptr->index].cost;
else {
if (i_ptr->p1 < 0)
value = 0;
else {
/* some digging tools start with non-zero p1 values, so only
* multiply the plusses by 100, make sure result is positive
* no longer; have adjusted costs in treasure.c -CWS
*/
value = i_ptr->cost + i_ptr->p1;
if (value < 0)
value = 0;
}
}
}
/* multiply value by number of items if it is a group stack item */
if (i_ptr->subval > ITEM_GROUP_MIN) /* do not include torches here */
value = value * i_ptr->number;
return (value);
}
/* Asking price for an item -RAK- */
int32
sell_price(snum, max_sell, min_sell, item)
int snum;
int32 *max_sell, *min_sell;
inven_type *item;
{
register int32 i;
register store_type *s_ptr;
s_ptr = &store[snum];
i = item_value(item);
/* check item->cost in case it is cursed, check i in case it is damaged */
if ((item->cost > 0) && (i > 0)) {
i = i * rgold_adj[owners[s_ptr->owner].owner_race][py.misc.prace] / 100;
if (i < 1)
i = 1;
*max_sell = i * owners[s_ptr->owner].max_inflate / 100;
*min_sell = i * owners[s_ptr->owner].min_inflate / 100;
if (snum == 6) {
(*max_sell) *= 2;
(*min_sell) *= 2;
}
if (*min_sell > *max_sell)
*min_sell = *max_sell;
return (i);
} else
/* don't let the item get into the store inventory */
return (0);
}
/* Check to see if he will be carrying too many objects -RAK- */
int
store_check_num(t_ptr, store_num)
inven_type *t_ptr;
int store_num;
{
register int store_check, i;
register store_type *s_ptr;
register inven_type *i_ptr;
store_check = FALSE;
s_ptr = &store[store_num];
if (s_ptr->store_ctr < STORE_INVEN_MAX)
store_check = TRUE;
else if (t_ptr->subval >= ITEM_SINGLE_STACK_MIN)
for (i = 0; i < s_ptr->store_ctr; i++) {
i_ptr = &s_ptr->store_inven[i].sitem;
/* note: items with subval of gte ITEM_SINGLE_STACK_MAX only stack if
* their subvals match
*/
if (i_ptr->tval == t_ptr->tval && i_ptr->subval == t_ptr->subval
&& ((int)i_ptr->number + (int)t_ptr->number < 256)
&& (t_ptr->subval < ITEM_GROUP_MIN
|| (i_ptr->p1 == t_ptr->p1)))
store_check = TRUE;
}
/* But, wait. If at home, don't let player drop 25th item, or he will lose it. -CFT */
if (is_home && (t_ptr->subval >= ITEM_SINGLE_STACK_MIN))
for (i = 0; i < s_ptr->store_ctr; i++) {
i_ptr = &s_ptr->store_inven[i].sitem;
/*
* note: items with subval of gte ITEM_SINGLE_STACK_MAX only stack if
* their subvals match
*/
if (i_ptr->tval == t_ptr->tval && i_ptr->subval == t_ptr->subval
&& ((int)i_ptr->number + (int)t_ptr->number > 24)
&& (t_ptr->subval < ITEM_GROUP_MIN
|| (i_ptr->p1 == t_ptr->p1)))
store_check = FALSE;
}
return (store_check);
}
/* Insert INVEN_MAX at given location */
static void
insert_store(store_num, pos, icost, i_ptr)
register int pos;
int store_num;
int32 icost;
inven_type *i_ptr;
{
register int i;
register store_type *s_ptr;
s_ptr = &store[store_num];
for (i = s_ptr->store_ctr - 1; i >= pos; i--)
s_ptr->store_inven[i + 1] = s_ptr->store_inven[i];
s_ptr->store_inven[pos].sitem = *i_ptr;
s_ptr->store_inven[pos].scost = (-icost);
s_ptr->store_ctr++;
}
/* Add the item in INVEN_MAX to stores inventory. -RAK- */
void
store_carry(store_num, ipos, t_ptr)
int store_num;
int *ipos;
inven_type *t_ptr;
{
int item_num, item_val, flag;
register int typ, subt;
int32 icost, dummy;
register inven_type *i_ptr;
register store_type *s_ptr;
int stacked = FALSE; /* from inven_carry() -CFT */
*ipos = -1;
if (sell_price(store_num, &icost, &dummy, t_ptr) > 0 || is_home)
{
s_ptr = &store[store_num];
item_val = 0;
item_num = t_ptr->number;
flag = FALSE;
typ = t_ptr->tval;
subt = t_ptr->subval;
if (subt >= ITEM_SINGLE_STACK_MIN) { /* try to stack in store's inven */
do {
i_ptr = &s_ptr->store_inven[item_val].sitem;
if (typ == i_ptr->tval)
{
if (subt == i_ptr->subval && /* Adds to other item */
subt >= ITEM_SINGLE_STACK_MIN
&& (subt < ITEM_GROUP_MIN || i_ptr->p1 == t_ptr->p1))
{
stacked = TRUE; /* remember that we did stack it... -CFT */
*ipos = item_val;
i_ptr->number += item_num;
/* must set new scost for group items, do this only for items
strictly greater than group_min, not for torches, this
must be recalculated for entire group */
if (subt > ITEM_GROUP_MIN)
{
(void) sell_price (store_num, &icost, &dummy, i_ptr);
s_ptr->store_inven[item_val].scost = -icost;
}
/* must let group objects (except torches) stack over 24
since there may be more than 24 in the group */
else if (i_ptr->number > 24)
i_ptr->number = 24;
flag = TRUE;
}
}
item_val ++;
} while (!stacked && (item_val < s_ptr->store_ctr));
} /* if might stack... -CFT */
if (!stacked) { /* either never stacks, or didn't find a place to stack */
item_val = 0;
do {
i_ptr = &s_ptr->store_inven[item_val].sitem;
if ((typ > i_ptr->tval) || /* sort by desc tval, */
((typ == i_ptr->tval) &&
((t_ptr->level < i_ptr->level) || /* then by inc level, */
((t_ptr->level == i_ptr->level) &&
(subt < i_ptr->subval))))) /* and finally by inc subval -CFT */
{ /* Insert into list */
insert_store(store_num, item_val, icost, t_ptr);
flag = TRUE;
*ipos = item_val;
}
item_val++;
} while ((item_val < s_ptr->store_ctr) && (!flag));
} /* if didn't already stack it... */
if (!flag) /* Becomes last item in list */
{
insert_store(store_num, (int)s_ptr->store_ctr, icost, t_ptr);
*ipos = s_ptr->store_ctr - 1;
}
}
}
/* Destroy an item in the stores inventory. Note that if */
/* "one_of" is false, an entire slot is destroyed -RAK- */
void
store_destroy(store_num, item_val, one_of)
int store_num, item_val;
int one_of;
{
register int j, number;
register store_type *s_ptr;
register inven_type *i_ptr;
s_ptr = &store[store_num];
i_ptr = &s_ptr->store_inven[item_val].sitem;
/* for single stackable objects, only destroy one half on average, this will
* help ensure that general store and alchemist have reasonable selection of
* objects
*/
if ((i_ptr->subval >= ITEM_SINGLE_STACK_MIN) &&
(i_ptr->subval <= ITEM_SINGLE_STACK_MAX)) {
if (one_of)
number = 1;
else
number = randint((int)i_ptr->number);
} else
number = i_ptr->number;
if (number != i_ptr->number)
i_ptr->number -= number;
else {
for (j = item_val; j < s_ptr->store_ctr - 1; j++)
s_ptr->store_inven[j] = s_ptr->store_inven[j + 1];
invcopy(&s_ptr->store_inven[s_ptr->store_ctr - 1].sitem, OBJ_NOTHING);
s_ptr->store_inven[s_ptr->store_ctr - 1].scost = 0;
s_ptr->store_ctr--;
}
}
/* Initializes the stores with owners -RAK- */
void
store_init()
{
register int i, j, k;
register store_type *s_ptr;
i = MAX_OWNERS / MAX_STORES;
for (j = 0; j < MAX_STORES; j++) {
s_ptr = &store[j];
s_ptr->owner = MAX_STORES * (randint(i) - 1) + j;
s_ptr->insult_cur = 0;
s_ptr->store_open = 0;
s_ptr->store_ctr = 0;
s_ptr->good_buy = 0;
s_ptr->bad_buy = 0;
for (k = 0; k < STORE_INVEN_MAX; k++) {
invcopy(&s_ptr->store_inven[k].sitem, OBJ_NOTHING);
s_ptr->store_inven[k].scost = 0;
}
}
}
/* Creates an item and inserts it into store's inven -RAK- */
static void
store_create(store_num)
int store_num;
{
register int i, tries;
int cur_pos, dummy;
register store_type *s_ptr;
register inven_type *t_ptr;
tries = 0;
cur_pos = popt();
s_ptr = &store[store_num];
object_level = OBJ_TOWN_LEVEL;
do {
if (store_num != 6) {
i = store_choice[store_num][randint(STORE_CHOICES) - 1];
invcopy(&t_list[cur_pos], i);
magic_treasure(cur_pos, OBJ_TOWN_LEVEL, FALSE, TRUE);
t_ptr = &t_list[cur_pos];
if (store_check_num(t_ptr, store_num)) {
if ((t_ptr->cost > 0) && /* Item must be good */
(t_ptr->cost < owners[s_ptr->owner].max_cost)) {
/* equivalent to calling ident_spell(), except will not change the object_ident array */
store_bought(t_ptr);
special_offer(t_ptr);
store_carry(store_num, &dummy, t_ptr);
tries = 10;
}
}
tries++;
} else {
i = get_obj_num(40, FALSE);
invcopy(&t_list[cur_pos], i);
magic_treasure(cur_pos, 40, FALSE, TRUE);
t_ptr = &t_list[cur_pos];
if (store_check_num(t_ptr, store_num)) {
if (t_ptr->cost > 0) { /* Item must be good */
/*
* equivalent to calling ident_spell(), except will not
* change the object_ident array
*/
store_bought(t_ptr);
special_offer(t_ptr);
store_carry(store_num, &dummy, t_ptr);
tries = 10;
}
}
tries++;
}
}
while (tries <= 3);
pusht(cur_pos);
}
static void
special_offer(i_ptr)
inven_type *i_ptr;
{
int32 orig_cost = i_ptr->cost;
if (randint(30) == 1) {
i_ptr->cost = (i_ptr->cost * 3) / 4;
if (i_ptr->cost < 1)
i_ptr->cost = 1;
if (i_ptr->cost < orig_cost)
inscribe(i_ptr, "25% discount");
} else if (randint(150) == 1) {
i_ptr->cost /= 2;
if (i_ptr->cost < 1)
i_ptr->cost = 1;
if (i_ptr->cost < orig_cost)
inscribe(i_ptr, "50% discount");
} else if (randint(300) == 1) {
i_ptr->cost /= 4;
if (i_ptr->cost < 1)
i_ptr->cost = 1;
if (i_ptr->cost < orig_cost)
inscribe(i_ptr, "75% discount");
} else if (randint(500) == 1) {
i_ptr->cost /= 10;
if (i_ptr->cost < 1)
i_ptr->cost = 1;
if (i_ptr->cost < orig_cost)
inscribe(i_ptr, "to clear");
}
}
/* Initialize and up-keep the store's inventory. -RAK- */
void
store_maint()
{
register int i, j;
register store_type *s_ptr;
for (i = 0; i < (MAX_STORES - 1); i++) {
s_ptr = &store[i];
s_ptr->insult_cur = 0;
if (s_ptr->store_ctr >= STORE_MIN_INVEN) {
j = randint(STORE_TURN_AROUND);
if (s_ptr->store_ctr >= STORE_MAX_INVEN)
j += 1 + s_ptr->store_ctr - STORE_MAX_INVEN;
while (--j >= 0)
store_destroy(i, randint((int)s_ptr->store_ctr) - 1, FALSE);
}
if (s_ptr->store_ctr <= STORE_MAX_INVEN) {
j = randint(STORE_TURN_AROUND);
if (s_ptr->store_ctr < STORE_MIN_INVEN)
j += STORE_MIN_INVEN - s_ptr->store_ctr;
while (--j >= 0)
store_create(i);
}
}
}
/* eliminate need to bargain if player has haggled well in the past -DJB- */
int
noneedtobargain(store_num, minprice)
int store_num;
int32 minprice;
{
register int flagnoneed;
register store_type *s_ptr;
if (no_haggle_flag)
return (TRUE);
s_ptr = &store[store_num];
flagnoneed = ((s_ptr->good_buy == MAX_SHORT)
|| ((s_ptr->good_buy - 3 * s_ptr->bad_buy) > (5 + (minprice/50))));
return (flagnoneed);
}
/* update the bargin info -DJB- */
void
updatebargain(store_num, price, minprice)
int store_num;
int32 price, minprice;
{
register store_type *s_ptr;
s_ptr = &store[store_num];
if (minprice > 9)
if (price == minprice) {
if (s_ptr->good_buy < MAX_SHORT)
s_ptr->good_buy++;
} else {
if (s_ptr->bad_buy < MAX_SHORT)
s_ptr->bad_buy++;
}
}